{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 创建和评估方案 <a class=\"anchor\" id=\"top\"></a>\n",
    "\n",
    "在此notebook中,您将使用Amazon Personalize训练几个特定模型: \n",
    "\n",
    "1. 用户个性化 - 给定用户最相关的物品.\n",
    "1. 相似物品 - 给定一个物品的相似物品.\n",
    "1. 个性化排序 - 给定一个用户和一组物品, 按他们最相关性排序.\n",
    "\n",
    "## 目录\n",
    "\n",
    "1. [简介](#intro)\n",
    "1. [创建方案](#solutions)\n",
    "1. [评估方案](#eval)\n",
    "1. [使用评估指标](#use)\n",
    "1. [存储有用的变量](#vars)\n",
    "\n",
    "## 简介 <a class=\"anchor\" id=\"intro\"></a>\n",
    "\n",
    "简单概述一下, 在Amazon Personalize 里面的算法（称为配方），大部分用来解决不同的任务, 解释如下:\n",
    "\n",
    "1. **User Personalization(用户个性化)** - 支持所有用户个性化需求, 将用于下面的实验.\n",
    "1. **HRNN & HRNN-Metadata(HRNN和HRNN元数据)** - 基于之前用户物品交互信息推荐物品.\n",
    "1. **HRNN-Coldstart(HRNN冷启动)** - 推荐没有交互信息的新物品.\n",
    "1. **Personalized-Ranking(个性化排序)** - 取一组物品，使用类HRNN方法按可能兴趣值对它们排序.\n",
    "1. **SIMS (相似物品)** - 给定一个物品, 推荐其他与用户有交互的物品.\n",
    "1. **Popularity-Count(热门程度-记数)** - 推荐最热门的物品, 如果HRNN或HRNN-Metadata没有结果 - 默认返回这个算法.\n",
    "\n",
    "无论在什么用户案例中, 所有算法都基于在用户物品交互数据上的学习,这些数据由下列3个属性定义:\n",
    "\n",
    "1. **UserID** - 用户\n",
    "1. **ItemID** - 物品\n",
    "1. **Timestamp** - 用户物品交互的时间\n",
    "\n",
    "也支持事件类型和事件值, 定义如下:\n",
    "\n",
    "1. **Event Type** - 事件的分类标签 (浏览, 购买, 打分, 等等).\n",
    "1. **Event Value** - 对应事件类型发生时的一个值. 一般来讲, 在时间类型之上归一化到0到1之间的值. 例如, 如果有3步完成一个交易 (点击, 放入购物车, 和购买), 那么每一步都单独有一个事件值如0.33, 0.66, 和 1.0.\n",
    "\n",
    "事件类型和事件值字段是附加数据，可以用来过滤用于个性化模型训练的数据. 这个练习不涉及事件类型和事件值. \n",
    "\n",
    "要运行此notebook, 您需要先运行完前面的notebooks, `01_Validating_and_Importing_User_Item_Interaction_Data` 和 `02_Validating_and_Importing_Item_Metadata.ipynb`, 之前您在Amazon Personalize里面创建了数据集并导入了交互数据和物品元数据. 在这些notebook结尾, 您保存了一些变量值, 这些值需要被加载到此notebook."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%store -r"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 创建方案 <a class=\"anchor\" id=\"solutions\"></a>\n",
    "[Back to top](#top)\n",
    "\n",
    "在此notebook, 您将创建使用了下列算法的方案:\n",
    "\n",
    "1. User Personalization(用户个性化)\n",
    "1. SIMS(相似物品)\n",
    "1. Personalized-Ranking(个性化排序)\n",
    "\n",
    "Popularity-Count(热门程度-记数) 算法是Amazon Personalize里面最简单的方案仅用于做基线方案用, 所以不在此notebook里面涉及.\n",
    "\n",
    "和之前的notebook类似, 从引入相关包开始, 使用SDK建立连接到Amazon Personalize."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import time\n",
    "from time import sleep\n",
    "import json\n",
    "\n",
    "import boto3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 配置SDK连接到Personalize:\n",
    "personalize = boto3.client('personalize')\n",
    "personalize_runtime = boto3.client('personalize-runtime')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在Amazon Personalize里面, 一个算法的特定变化被称为配方. 不同的配方适用于不同的场景. 一个训练好的模型被称为一个方案, 并且当模型被训练时每个方案可以有多个版本关联到给定数据.\n",
    "\n",
    "开始前, 先列出所有支持的配方. 您可以选择一个并用于构建您的模型."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "personalize.list_recipes()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "输出是JSON格式包含了在简介中谈到的所有算法.\n",
    "\n",
    "接下来选择指定配方并构建模型.\n",
    "\n",
    "### 用户个性化\n",
    "User-Personalization (aws-user-personalization) 配方已被优化用于所有的USER_PERSONALIZATION用户个性化推荐场景. 当推荐物品时, 它自动使用物品探索.\n",
    "\n",
    "使用物品探索, Amazon Personalize 自动测试不同的物品推荐, 从用户如何和推荐的物品交互中学习, 并增加推荐能带来更好交互和转化的物品. 当您有一个快速变化的目录时,或者当有和用户更相关的新物品时, 如新闻文章或促销, 这将增强物品的发现和交互.\n",
    "\n",
    "您可以平衡探索的程度 (较少交互数据或相关性的数据的物品更被频繁推荐) 和开发利用的程度 (推荐基于我们知道的或相关性). Amazon Personalize 自动基于隐式用户反馈调整未来推荐.\n",
    "\n",
    "首先, 从上面列出的配方中通过ARN选择配方."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "user_personalization_recipe_arn = \"arn:aws:personalize:::recipe/aws-user-personalization\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 创建方案\n",
    "\n",
    "首先使用这个配方创建一个方案. 虽然在这一步提供了数据集的ARN, 但是模型还没有被训练. 把这个视为一个标识符而不是一个已训练好的模型."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "user_personalization_create_solution_response = personalize.create_solution(\n",
    "    name = \"personalize-poc-userpersonalization\",\n",
    "    datasetGroupArn = dataset_group_arn,\n",
    "    recipeArn = user_personalization_recipe_arn\n",
    ")\n",
    "\n",
    "user_personalization_solution_arn = user_personalization_create_solution_response['solutionArn']\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(json.dumps(user_personalization_solution_arn, indent=2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 创建方案版本\n",
    "\n",
    "一旦有了方案, 您需要创建一个版本来完成模型训练. 训练需要一点时间完成, 超过25分钟, 使用这个配方和我们的数据集平均需要90分钟. 一般我们使用一个while循环进行轮询直到任务完成. 但是任务在执行时将阻止后续单元执行, 这里的目标是创建很多模型并快速部署它们. 所以我们将在此notebook中为后续所有方案设立while循环. 后面，您也将在亚马逊云科技控制台上查看运行的进度."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "userpersonalization_create_solution_version_response = personalize.create_solution_version(\n",
    "    solutionArn = user_personalization_solution_arn\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "userpersonalization_solution_version_arn = userpersonalization_create_solution_version_response['solutionVersionArn']\n",
    "print(json.dumps(user_personalization_create_solution_response, indent=2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### SIMS\n",
    "\n",
    "\n",
    "SIMS算法是Amazon推荐系统中使用到的最老的算法之一. 一个核心用户案例是您有个物品且您想按整个用户群和它交互过的方式推荐其它物品. 这意味着结果没有按用户进行个性化. 有时这导致一直推荐最热门的物品, 所以这里有个超参数可以微调来减少返回结果中的热门物品. \n",
    "\n",
    "这里的用户案例, 使用了Movielens 数据, 假设我们选择了某个电影. 那么我们可以使用SIMS基于整个用户群和这个电影交互的行为来推荐其他电影. 结果没有按用户个性化, 但是相反, 结果依输入电影不同而不同.\n",
    "\n",
    "像上次一样, 我们选择这个配方."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "SIMS_recipe_arn = \"arn:aws:personalize:::recipe/aws-sims\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 创建方案\n",
    "\n",
    "先创建方案，虽然在这一步提供了数据集的ARN，但是模型还没有被训练. 把这个视为一个标识符而不是一个已训练好的模型."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sims_create_solution_response = personalize.create_solution(\n",
    "    name = \"personalize-poc-sims\",\n",
    "    datasetGroupArn = dataset_group_arn,\n",
    "    recipeArn = SIMS_recipe_arn\n",
    ")\n",
    "\n",
    "sims_solution_arn = sims_create_solution_response['solutionArn']\n",
    "print(json.dumps(sims_create_solution_response, indent=2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 创建方案版本\n",
    "\n",
    "一旦有了方案, 您需要创建一个版本来完成模型训练. 训练需要一点时间完成, 超过25分钟, 使用这个配方和我们的数据集平均需要35分钟. 一般我们使用一个while循环进行轮询直到任务完成. 但是任务在执行时将阻止后续单元执行, 这里的目标是创建很多模型并快速部署它们. 所以我们将在此notebook中为后续所有方案设立while循环. 后面，您也将在亚马逊云科技控制台上查看运行的进度."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sims_create_solution_version_response = personalize.create_solution_version(\n",
    "    solutionArn = sims_solution_arn\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sims_solution_version_arn = sims_create_solution_version_response['solutionVersionArn']\n",
    "print(json.dumps(sims_create_solution_version_response, indent=2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 个性化排序\n",
    "\n",
    "Personalized Ranking(个性化排序)是一个有趣的应用. 这个算法使用一个用户和一个物品列表, 针对这个用户按最可信相关联性排序返回新的物品列表，而不是仅为用户推荐最可信的物品. 这里用到的用户案例用于过滤没有物品元数据的唯一分类来生成过滤器,或当您需要为特定用户排序一个大的物品列表时.\n",
    "\n",
    "这里的用户案例, 使用了Movielens 数据, 假设一个VOD应用需要创建一个连环漫画册电影影架, 或某个导演的电影集. 最可能我们使用这些标题元数据来生成列表. 使用个性化排序，基于用户之前的标记历史, 我们能够为每位用户重新排序电影列表. \n",
    "\n",
    "像上次一样, 我们选择这个配方."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "rerank_recipe_arn = \"arn:aws:personalize:::recipe/aws-personalized-ranking\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 创建方案\n",
    "\n",
    "如之前的方案一样, 先创建方案. 虽然在这一步提供了数据集的ARN, 但是模型还没有被训练. 把这个视为一个标识符而不是一个已训练好的模型."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "rerank_create_solution_response = personalize.create_solution(\n",
    "    name = \"personalize-poc-rerank\",\n",
    "    datasetGroupArn = dataset_group_arn,\n",
    "    recipeArn = rerank_recipe_arn\n",
    ")\n",
    "\n",
    "rerank_solution_arn = rerank_create_solution_response['solutionArn']\n",
    "print(json.dumps(rerank_create_solution_response, indent=2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 创建方案版本\n",
    "\n",
    "一旦有了方案, 您需要创建一个版本来完成模型训练. 训练需要一点时间完成, 超过25分钟, 使用这个配方和我们的数据集平均需要35分钟. 一般我们使用一个while循环进行轮询直到任务完成. 但是任务在执行时将阻止后续单元执行, 这里的目标是创建很多模型并快速部署它们. 所以我们将在此notebook中为后续所有方案设立while循环. 后面，您也将在亚马逊云科技控制台上查看运行的进度."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "rerank_create_solution_version_response = personalize.create_solution_version(\n",
    "    solutionArn = rerank_solution_arn\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "rerank_solution_version_arn = rerank_create_solution_version_response['solutionVersionArn']\n",
    "print(json.dumps(rerank_create_solution_version_response, indent=2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 查看方案创建状态\n",
    "\n",
    "如前面所承诺, 现在在亚马逊云科技控制台查看运行进度:\n",
    "\n",
    "* 在另一个浏览器页签中您应该已有打开的亚马逊云科技控制台. \n",
    "* 切换到那个页签, 搜索服务 `Personalize`,接着进入服务页面. \n",
    "* 点击 `View dataset groups`.\n",
    "* 点击您的数据集名称, 名称中很可能有POC.\n",
    "* 点击 `Solutions and recipes`.\n",
    "* 您将看到您上面创建的所有方案的一个列表, 包含了方案版本的状态列. 一旦状态变成 `Active`, 您的方案就可以被查看了. 它也能够被部署了.\n",
    "\n",
    "或简单运行下列单元来跟踪方案版本的创建状态."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "in_progress_solution_versions = [\n",
    "    userpersonalization_solution_version_arn,\n",
    "    sims_solution_version_arn,\n",
    "    rerank_solution_version_arn\n",
    "]\n",
    "\n",
    "max_time = time.time() + 10*60*60 # 10 hours\n",
    "while time.time() < max_time:\n",
    "    for solution_version_arn in in_progress_solution_versions:\n",
    "        version_response = personalize.describe_solution_version(\n",
    "            solutionVersionArn = solution_version_arn\n",
    "        )\n",
    "        status = version_response[\"solutionVersion\"][\"status\"]\n",
    "        \n",
    "        if status == \"ACTIVE\":\n",
    "            print(\"Build succeeded for {}\".format(solution_version_arn))\n",
    "            in_progress_solution_versions.remove(solution_version_arn)\n",
    "        elif status == \"CREATE FAILED\":\n",
    "            print(\"Build failed for {}\".format(solution_version_arn))\n",
    "            in_progress_solution_versions.remove(solution_version_arn)\n",
    "    \n",
    "    if len(in_progress_solution_versions) <= 0:\n",
    "        break\n",
    "    else:\n",
    "        print(\"At least one solution build is still in progress\")\n",
    "        \n",
    "    time.sleep(60)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 超参数调优\n",
    "\n",
    "Amazon Personalize提供了在创建方案时运行超参数调优的选项. 因为需要额外计算资源执行超参数调优, 这个特性默认是关闭的. 因此, 我们上面创建的方案将仅使用每个配方的默认超参数值. 如果要查看超参数调优的更多信息, 请查看 [documentation](https://docs.aws.amazon.com/personalize/latest/dg/customizing-solution-config-hpo.html).\n",
    "\n",
    "如果您确定了使用某个配方, 并准备好了进行超参数调优, 那么下列代码展示了如何操作, 以SIMS为例.\n",
    "\n",
    "```python\n",
    "sims_create_solution_response = personalize.create_solution(\n",
    "    name = \"personalize-poc-sims-hpo\",\n",
    "    datasetGroupArn = dataset_group_arn,\n",
    "    recipeArn = SIMS_recipe_arn,\n",
    "    performHPO=True\n",
    ")\n",
    "\n",
    "sims_solution_arn = sims_create_solution_response['solutionArn']\n",
    "print(json.dumps(sims_create_solution_response, indent=2))\n",
    "```\n",
    "\n",
    "如果您已经知道某个特定超参数的值, 您也可以直接在创建方案时设置这个值. 下列代码展示了为SIMS配方设置 `popularity_discount_factor` 参数值.\n",
    "\n",
    "```python\n",
    "sims_create_solution_response = personalize.create_solution(\n",
    "    name = \"personalize-poc-sims-set-hp\",\n",
    "    datasetGroupArn = dataset_group_arn,\n",
    "    recipeArn = SIMS_recipe_arn,\n",
    "    solutionConfig = {\n",
    "        'algorithmHyperParameters': {\n",
    "            'popularity_discount_factor': '0.7'\n",
    "        }\n",
    "    }\n",
    ")\n",
    "\n",
    "sims_solution_arn = sims_create_solution_response['solutionArn']\n",
    "print(json.dumps(sims_create_solution_response, indent=2))\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 评估方案版本 <a class=\"anchor\" id=\"eval\"></a>\n",
    "[Back to top](#top)\n",
    "\n",
    "训练此notebook中的所有方案不会超过1个小时. 当训练进行中时, 推荐您花点时间详细阅读不同的算法(配方)和它们的行为. 这也是一个好时机考虑如何输入数据到系统中的替代方案和期望看到什么类型的结果.\n",
    "\n",
    "当方案创建完成,下一步是获取评估指标. Amazon Personalize 基于训练数据的子集来计算这些指标. 下图演示了Amazon Personalize如何分割数据. 给定10个用户, 每个10个交互 (一个圆圈表示一个交互), 基于时间戳从最老到最新对交互进行排序. Amazon Personalize 使用90%的用户(蓝圈)的交互数据来训练方案版本, 剩下10%用于评估. 在评估数据集中的每个用户, 90%的交互数据(绿圈)被用来作为输入去调用训练过的模型. 剩下的10%的数据 (橙色圈) 被用于比较模型的输出, 被用来计算评估指标.\n",
    "\n",
    "![personalize metrics](static/imgs/personalize_metrics.png)\n",
    "\n",
    "推荐阅读文档来理解这些指标 [the documentation](https://docs.aws.amazon.com/personalize/latest/dg/working-with-training-metrics.html) , 未来方便我们也拷贝了部分文档如下.\n",
    "\n",
    "关于Amazon Personalize中的评估,您需要理解下列术语:\n",
    "\n",
    "* *Relevant recommendation(关联推荐)* 是指与特定用户测试数据中的值相匹配的推荐.\n",
    "* *Rank(排序)* 是指推荐的物品在推荐列表中的位置. 位置 1 (列表中的最高位) 假定为和该用户最相关的.\n",
    "* *Query(查询)* 是指和 GetRecommendations 接口调用的内部相等操作.\n",
    "\n",
    "Amazon Personalize产生的指标如下:\n",
    "* **coverage**:唯一推荐物品数量与训练数据(包括物品和交互数据集)中的唯一物品的总数的比例 .\n",
    "* **mean_reciprocal_rank_at_25**: 所有查询中前25推荐中的第一相关推荐的[mean of the reciprocal ranks(倒数排序的平均值)](https://en.wikipedia.org/wiki/Mean_reciprocal_rank).如果您对单个排名最高的推荐感兴趣，那么此指标是合适的.\n",
    "\n",
    "* **normalized_discounted_cumulative_gain_at_K**: 折扣增益假定推荐列表中排名较低的推荐与排名较高的推荐相比相关性更低。因此，每个推荐被折扣一倍（给定较低的权重），具体取决于其位置。为了在 K 处产生[累积折扣增益 (DCG)](https://en.wikipedia.org/wiki/Discounted_cumulative_gain)，前 K 个推荐中的每个相关折扣推荐被相加。归一化折扣累计增益 (NDCG) 是 DCG 除以理想 DCG，使得 NDCG 在 0-1 之间。（在理想 DCG 中，前 K 个推荐将按相关性进行排序。）Amazon Personalize 使用了加权系数 1/log(1 + position)，其中列表的顶部是位置 1。此指标奖励出现在列表顶部附近的相关项目，因为列表顶部通常会引起更多关注。\n",
    "\n",
    "* **precision_at_K**: 前 K 个推荐中的相关推荐数除以 K。此指标奖励相关项目的精准推荐。\n",
    "\n",
    "接下来, 让我们看看此notebook中生成的方案的各个评估指标. *注意, 您的结果可能和此notebook中描述的文本不一致, 因为Movielens数据集的质量.* \n",
    "\n",
    "### 用户个性化指标\n",
    "\n",
    "首先, 提取User Personalization(用户个性化)方案版本的评估指标."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "user_personalization_solution_metrics_response = personalize.get_solution_metrics(\n",
    "    solutionVersionArn = userpersonalization_solution_version_arn\n",
    ")\n",
    "\n",
    "print(json.dumps(user_personalization_solution_metrics_response, indent=2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "上述归一化折扣累计增益告诉我们, 5个物品低于(38% full, 22% small) 机会被推荐，推荐作为该用户的交互历史的一部分(在训练和验证维持阶段). 大约 13% 推荐的物品是唯一的, 并且前5被推荐的物品的精确度仅是(14% full, 7.5% small) . \n",
    "\n",
    "很明显这不是一个了不起的模型, 但是要记住我们必须使用我们交互的评级数据,因为Movielens是一个基于评级的显示数据集. 时间戳也是电影被评级时的时间, 不是观看的时间,所以这个排序和观影者观看电影的排序不一样.\n",
    "\n",
    "### SIMS 指标\n",
    "\n",
    "现在, 为SIMS方案版本提取评估指标"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sims_solution_metrics_response = personalize.get_solution_metrics(\n",
    "    solutionVersionArn = sims_solution_version_arn\n",
    ")\n",
    "\n",
    "print(json.dumps(sims_solution_metrics_response, indent=2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在这个例子中我们查看到5个物品上轻微的精确度提升,这次有一点提升 (4.5% full, 6.4% small) . 实际上在错误范围内这是可信的, 但是给定这个对mask热门没有造成影响, 它可能从某种方式仅返回了大量有交互的用户的超级热门结果. \n",
    "\n",
    "### 个性化排序指标\n",
    "\n",
    "现在, 为个性化排序方案版本提取评估指标"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "rerank_solution_metrics_response = personalize.get_solution_metrics(\n",
    "    solutionVersionArn = rerank_solution_version_arn\n",
    ")\n",
    "\n",
    "print(json.dumps(rerank_solution_metrics_response, indent=2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "快速评论一下, 这里我们看到精确度近乎(2.7% full, 2.2% small), 因为这基于用户个性化, 结果是预想中的. 但是抽样物品与验证物品不同，因此分数较低.\n",
    "\n",
    "## 使用评估指标 <a class=\"anchor\" id=\"use\"></a>\n",
    "[Back to top](#top)\n",
    "\n",
    "仔细使用评估指标很重要. 这里有些因素要记住.\n",
    "\n",
    "* 如果已有在用推荐系统, 这将影响用于训练您的方案的用户的交互历史. 这意味着评估指标是对已有方案有偏好. 如果您推进评估指标匹配或超出已有方案, 您可能只是在推进用户个性化像已有方案去表现，可能不会有更好的结果.\n",
    "* HRNN Coldstart(HRNN冷启动)配方使用Amazon Personalize产生的指标去评估是困难的. 这个配方的目标是推荐业务上新的物品. 因此, 这些物品不会出现在用于计算评估指标的已有用户交易数据中. 结果是, 当单比较评估指标时, HRNN 冷启动永不会比其他配方表现得好. 注意: 用户个性化配方也包括增强的冷启动功能.\n",
    "\n",
    "记住这些因素, Amazon Personalize产生的评估指标通常对两类案例有用:\n",
    "1. 比较相同配方训练出的方案版本性能, 但是使用不同的超参数值和特征(隐藏数据等)\n",
    "1. 比较不同配方训练出的方案版本性能(不包含HRNN冷启动).\n",
    "\n",
    "正确地评估一个推荐系统总是最好通过A/B测试测量实际业务输出而完成. 因为系统产生的推荐通常影响它所依赖的用户行为,最好运行一长段时间小型试验和A/B测试. 随着时间的过去, 来自已有模型的偏差将逐渐变淡."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 存储有用的变量 <a class=\"anchor\" id=\"vars\"></a>\n",
    "[Back to top](#top)\n",
    "\n",
    "在退出此notebook前, 请运行下列单元来保存版本 ARNs用于后续notebook."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%store userpersonalization_solution_version_arn\n",
    "%store sims_solution_version_arn\n",
    "%store rerank_solution_version_arn\n",
    "%store user_personalization_solution_arn\n",
    "%store sims_solution_arn\n",
    "%store rerank_solution_arn"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "conda_python3",
   "language": "python",
   "name": "conda_python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
